<template>
  <div class="hello">
    <div class='contain' @dragenter="handleDrag" @dragover="handleDrag" @drop="handleDrag" @dragleave="handleDrag">
      <div class="upload-c">
        上传
      </div>
    </div>
    {{ processLineArrayComputed }}
    <div class="show-c">
      <img v-if="nowFileType === 'img'" :src="urlItem" alt="" />
      <video v-if="nowFileType === 'video'" :src="urlItem" alt=""></video>
    </div>
    <div class="upload-btn" @click="handleSubmit">
      提交
    </div>
    <div class="upload-btn" @click="handlePause">
      暂停
    </div>
    <div class="upload-btn" @click="handleResume">
      恢复上传
    </div>
  </div>
</template>

<script setup>
import { MAX_FILE_SIZE, CHUNK_SIZE } from '@/utils/constants';
import request from '@/utils/request';
import axios from 'axios';

import { ref, computed } from 'vue';
const nowFile = ref(null);
const urlItem = ref(null);
const processLineArray = ref({})
const nowUploadFileSize = ref(0)

const nowFileType = ref('')
const cal = new Worker('/fileName.js')
const cancelTokenArr = ref([])

const UploadStatus = {
  NOT_STARTED: 'NOT_STARTED',
  UPLOADING:'UPLOADING',
  PUSED: 'PUSED'
}

const nowUploadStatus = ref(UploadStatus.NOT_STARTED)


const processLineArrayComputed = computed(() => {
  const totalV = Object.values(processLineArray.value).reduce((a, b) => a + b, 0);
  return Math.round((totalV / nowUploadFileSize.value) * 100) || 0
})

function handleDrag (e) {
  console.log('jfasjjafs')
  e.preventDefault()
  e.stopPropagation()
  const files = e.dataTransfer.files;
  if (checkFile(files)) {
    showFiles(files)
    nowFile.value = files[0];
  }
}

function showFiles (files) {
  const file = files[0];
  urlItem.value = URL.createObjectURL(file);

  if (file.type.startsWith('image/')) {
    nowFileType.value = 'img'
  } else if (file.type.startsWith('video/')) {
    nowFileType.value = 'video'
  }

}

function checkFile (files) {
  const file = files[0];
  if (!file) {
    return
  }
  if (file.size > MAX_FILE_SIZE) {
    return alert('文件大小不能超过2g')
  }

  if (!(file.type.startsWith('image/') || file.type.startsWith('video/'))) {
    return alert('文件类型只能是图片或视频')
  }
  return true
}

async function handleSubmit () {
  if (!nowFile.value) return alert('请上传文件');
  // const fileName = await getFileName(nowFile.value)

  cal.postMessage(nowFile.value)

  cal.addEventListener('message', (e) => {
      uploadFile(nowFile.value, e.data)
  })

  /**
   * 上传文件
   * 1. 大文件切片.
  */
  //  uploadFile(nowFile.value, fileName)
}

async function handlePause() {

  nowUploadStatus.value = UploadStatus.PUSED
  cancelTokenArr.value.forEach(cancelToken => {
    cancelToken.cancel()
  })
}
async function handleResume() {
  console.log('暂停')
}

async function uploadFile (file, fileName) {

  debugger

  const { needUpload, uploadList } = await request.get('/verify/'+fileName)


  if(!needUpload) return alert('上传成功')
  nowUploadStatus.value = UploadStatus.UPLOADING
  nowUploadFileSize.value = file.size;
  // 切片
  const chunks = createFileChunks(file, fileName)
  // 上传
  const requests = chunks.map(chunk => {
    const source = axios.CancelToken.source(); // 取消
    cancelTokenArr.value.push(source);

    const checkUploadChunk = uploadList.find(item => item.chunkFileName === chunk.chunkFileName)
    if(checkUploadChunk) {
      const { size: uploadSize } = checkUploadChunk;
      const remainingChunk = {
        chunkFileName: chunk.chunkFileName,
        chunk: chunk.chunk.slice(uploadSize)
      } 

      if(uploadSize === chunk.chunk.size) {
        processLineArray.value[chunk.chunkFileName] = uploadSize
        console.log(fileName)
        return  
      } 
      return createRequest(remainingChunk, fileName, createProcess, source, uploadSize)
    } else {
      return createRequest(chunk, fileName, createProcess, source, 0)
    }

  })

  function createProcess(event,chunkFileName, start) {
    // const processNum = Math.round((event.loaded / event.total) * 100)
    processLineArray.value[chunkFileName] = event.loaded + start
  }

  try {
     await Promise.all(requests)
    const res = await request.get(`/merge/${fileName}`)
    console.log(res)
    alert('上传成1功')
    processLineArray.value = {}
  } catch (error) {
    console.log(error, '-------------------------------')
    alert('上传gg')
  }

}



function createRequest(fileItem, fileName, fn, source, start) {
      const {chunkFileName, chunk: file} = fileItem;
      console.log(chunkFileName, file)
      return request.post(`/upload/${fileName}`, file, {
        headers: {
          'Content-Type': 'application/octet-stream'
        },
        params: {
          chunkFileName, 
          start
        },
        onUploadProgress: (event) => fn(event, chunkFileName, start),
        cancelToken: source.token
      })
    }


function createFileChunks (file, fileName) {
  const chunks = [];
  // 切片数
  const count = Math.ceil(file.size / CHUNK_SIZE);
  console.log(count, 'countcountcountcount')
  for (let i = 0; i < count; i++) {
    const chunk = file.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
    chunks.push({
      chunk,
      chunkFileName: `${fileName}-${i}`
    })
  }
  return chunks
} 


// async function getFileName (file) {
//   const fileHash = await calculateFileHash(file);
//   // 文件名
//   const fileExtension = file.name.split('.').pop();
//   return `${fileHash}.${fileExtension}`
// }


// async function calculateFileHash (file) {
//   console.log(file)
//   debugger
//   const arrayBuffer = await file.arrayBuffer()
//   // crypto.subtle.digest加密
//   const hashBuffer = await crypto.subtle.digest('SHA-256', arrayBuffer);
//   // hashBuffer 是二进制,需要转十进制
//   return bufferToHex(hashBuffer)
// }

// // 将一个arrayBuffer 转成16进制的字符串
// function bufferToHex (hashBuffer) {
//   // buffer转字符串
//   return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')
// }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
* {
  margin: 0;
  padding: 0;
}

li {
  list-style: none
}

.upload-c {
  width: 80%;
  margin: auto;
  border: 1px solid #e64f4f;
  height: 100px;
  text-align: center;
  line-height: 100px;
  margin-top: 20px;
}

.upload-btn {
  width: 100px;
  text-align: center;
  height: 30px;
  line-height: 30px;
  margin: auto;
  margin-top: 20px;
  border: 1px solid red;
}

.show-c {
  width: 100px;
}
.show-c img {
  width: 100px;
}
.show-c video {
  width: 100px;
}
</style>
